﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace IslandInterloper.Engine
{
    public static class Command
    {
        #region CommandValues
        internal enum CommandValue
        {
            StartGame,
            GetAvatarInformation,
            GetIslandInformation,
            ToggleIslandBookmark,
            AnnotateIsland,
            Undock,
            GetDockableIslandList,
            GetNearByIslandList,
            Dock,
            GetAvatarSpeedInformation,
            SetSpeed,
            SetHeading,
            Sail,
            SetBoundForIsland,
            GetKnownIslandList,
            GetCommodityInformation,
            GetShipInformation,
            GetAvatarSpeedList,
            BuyCommodity,
            SellCommodity,
            GetCrewmemberInformation
        }
        private const CommandValue DefaultCommandValue = CommandValue.GetAvatarInformation;
        #endregion
        #region Framework
        private static XElement CreateCommand(CommandValue theCommandValue)
        {
            return new XElement(GameXNames.root, new XElement(GameXNames.command, theCommandValue), new XElement(GameXNames.payload));
        }
        private static bool ValidateCommand(XElement root, out CommandValue theResultValue)
        {
            theResultValue = DefaultCommandValue;
            return (root.Name.LocalName == GameXNames.root && root.Element(GameXNames.command) != null && root.Element(GameXNames.payload) != null && Enum.TryParse<CommandValue>(root.Element(GameXNames.command).Value, out theResultValue));
        }
        private static bool ValidateCommand(XElement root)
        {
            CommandValue theResultValue;
            return ValidateCommand(root, out theResultValue);
        }
        private static XElement GetPayload(XElement root)
        {
            if (ValidateCommand(root))
            {
                return root.Element(GameXNames.payload);
            }
            else
            {
                return null;
            }
        }
        internal static CommandValue GetCommand(XElement root, out bool success)
        {
            CommandValue result = DefaultCommandValue;
            success = ValidateCommand(root, out result);
            return result;
        }
        internal static CommandValue GetCommand(XElement root)
        {
            bool success = false;
            return GetCommand(root, out success);
        }
        #endregion
        #region Start Game
        public static XElement CreateStartGameCommand()
        {
            return CreateCommand(CommandValue.StartGame);
        }
        #endregion
        #region Sail
        public static XElement CreateSailCommand()
        {
            return CreateCommand(CommandValue.Sail);
        }
        #endregion
        #region Get Avatar Information
        public static XElement CreateGetAvatarInformationCommand()
        {
            return CreateCommand(CommandValue.GetAvatarInformation);
        }
        #endregion
        #region Undock
        public static XElement CreateUndockCommand()
        {
            return CreateCommand(CommandValue.Undock);
        }
        #endregion
        #region Get Dockable Island List
        public static XElement CreateGetDockableIslandListCommand()
        {
            return CreateCommand(CommandValue.GetDockableIslandList);
        }
        #endregion
        #region Get Near By Island List
        public static XElement CreateGetNearByIslandListCommand()
        {
            return CreateCommand(CommandValue.GetNearByIslandList);
        }
        #endregion
        #region Get Known Island List
        public static XElement CreateGetKnownIslandListCommand()
        {
            return CreateCommand(CommandValue.GetKnownIslandList);
        }
        #endregion
        #region Get Avatar Speed List
        public static XElement CreateGetAvatarSpeedListCommand()
        {
            return CreateCommand(CommandValue.GetAvatarSpeedList);
        }
        #endregion
        #region Get Avatar Speed Information
        public static XElement CreateGetAvatarSpeedInformationCommand(string speed)
        {
            XElement result =  CreateCommand(CommandValue.GetAvatarSpeedInformation);
            GetPayload(result).Add(new XElement(GameXNames.speed, speed.ToString()));
            return result;
        }
        #endregion
        #region Set Heading
        public static XElement CreateSetHeadingCommand(int theDegrees, int theMinutes, double theSeconds)
        {
            XElement result = CreateCommand(CommandValue.SetHeading);
            GetPayload(result).Add(new XElement(GameXNames.heading, (double)theDegrees+(double)(theMinutes/60.0)+theSeconds/60/60));
            return result;
        }
        internal static double GetHeading(XElement root, out bool success)
        {
            return Payload.GetDouble(GetPayload(root), GameXNames.heading, out success, 0.0);
        }
        internal static double GetHeading(XElement root)
        {
            bool success = false;
            return GetHeading(root, out success);
        }
        #endregion
        #region Get Island Information
        public static XElement CreateGetIslandInformationCommand(int theIslandId)
        {
            XElement result = CreateCommand(CommandValue.GetIslandInformation);
            GetPayload(result).Add(new XElement(GameXNames.islandId,theIslandId));
            return result;
        }
        internal static int GetIslandId(XElement root, out bool success)
        {
            int result = -1;
            success = false;
            if (ValidateCommand(root))
            {
                XElement islandId = GetPayload(root).Element(GameXNames.islandId);
                if (islandId != null)
                {
                    success = int.TryParse(islandId.Value, out result);
                }
            }
            return result;
        }
        internal static int GetIslandId(XElement root)
        {
            bool success;
            return GetIslandId(root, out success);
        }
        #endregion
        #region Set Avatar Speed
        public static XElement CreateSetAvatarSpeedCommand(string theAvatarSpeed)
        {
            XElement result = CreateCommand(CommandValue.SetSpeed);
            GetPayload(result).Add(new XElement(GameXNames.speed, theAvatarSpeed));
            return result;
        }
        internal static string GetAvatarSpeed(XElement root, out bool success)
        {
            return Payload.GetString(GetPayload(root), GameXNames.speed, out success, string.Empty);
        }
        internal static string GetAvatarSpeed(XElement root)
        {
            bool success = false;
            return GetAvatarSpeed(root, out success);
        }
        #endregion
        #region Dock
        public static XElement CreateDockCommand(int theIslandId)
        {
            XElement result = CreateCommand(CommandValue.Dock);
            GetPayload(result).Add(new XElement(GameXNames.islandId, theIslandId));
            return result;
        }
        #endregion
        #region Toggle Island Bookmark
        public static XElement CreateToggleIslandBookmarkCommand(int theIslandId)
        {
            XElement result = CreateCommand(CommandValue.ToggleIslandBookmark);
            GetPayload(result).Add(new XElement(GameXNames.islandId, theIslandId));
            return result;
        }
        #endregion
        #region Set Bound For Island
        public static XElement CreateSetBoundForIslandCommand(int theIslandId)
        {
            XElement result = CreateCommand(CommandValue.SetBoundForIsland);
            GetPayload(result).Add(new XElement(GameXNames.islandId, theIslandId));
            return result;
        }
        #endregion
        #region Annotate Island
        public static XElement CreateAnnotateIslandCommand(int theIslandId, string theNotes)
        {
            XElement result = CreateCommand(CommandValue.AnnotateIsland);
            GetPayload(result).Add(new XElement(GameXNames.islandId, theIslandId),
                new XElement(GameXNames.notes,theNotes));
            return result;
        }
        internal static string GetNotes(XElement root, out bool success)
        {
            return Payload.GetString(GetPayload(root), GameXNames.notes, out success, string.Empty);
        }
        internal static string GetNotes(XElement root)
        {
            bool success = false;
            return GetNotes(root, out success);
        }
        #endregion
        #region Get Commodity Information
        public static XElement CreateGetCommodityInformationCommand(string commodity)
        {
            XElement result = CreateCommand(CommandValue.GetCommodityInformation);
            GetPayload(result).Add(new XElement(GameXNames.commodity, commodity));
            return result;
        }
        internal static string GetCommodity(XElement root, out bool success)
        {
            return Payload.GetString(GetPayload(root), GameXNames.commodity, out success, string.Empty);
        }
        internal static string GetCommodity(XElement root)
        {
            bool success;
            return GetCommodity(root, out success);
        }
        #endregion
        #region Get Ship Information
        public static XElement CreateGetShipInformationCommand(string ship)
        {
            XElement result = CreateCommand(CommandValue.GetShipInformation);
            GetPayload(result).Add(new XElement(GameXNames.ship, ship));
            return result;
        }
        public static string GetShip(XElement root, out bool success)
        {
            return Payload.GetString(GetPayload(root),GameXNames.ship,out success, string.Empty);
        }
        public static string GetShip(XElement root)
        {
            bool success;
            return GetShip(root, out success);
        }
        #endregion
        #region Buy Commodity
        public static XElement CreateBuyCommodityCommand(string commodity, double units)
        {
            XElement result = CreateCommand(CommandValue.BuyCommodity);
            GetPayload(result).Add(new XElement(GameXNames.commodity, commodity));
            GetPayload(result).Add(new XElement(GameXNames.units, units));
            return result;
        }
        internal static double GetUnits(XElement root, out bool success)
        {
            return Payload.GetDouble(GetPayload(root), GameXNames.units, out success, 0.0);
        }
        internal static double GetUnits(XElement root)
        {
            bool success;
            return GetUnits(root, out success);
        }
        #endregion
        #region Sell Commodity
        public static XElement CreateSellCommodityCommand(string commodity, double units)
        {
            XElement result = CreateCommand(CommandValue.SellCommodity);
            GetPayload(result).Add(new XElement(GameXNames.commodity, commodity));
            GetPayload(result).Add(new XElement(GameXNames.units, units));
            return result;
        }
        #endregion
        #region Get Crewmember Information
        public static XElement CreateGetCrewmemberInformationCommand(string theCrewmember)
        {
            XElement result = CreateCommand(CommandValue.GetCrewmemberInformation);
            GetPayload(result).Add(new XElement(GameXNames.crewmember, theCrewmember));
            return result;
        }
        internal static string GetCrewmember(XElement root, out bool success)
        {
            return Payload.GetString(GetPayload(root), GameXNames.crewmember, out success, string.Empty);
        }
        internal static string GetCrewmember(XElement root)
        {
            bool success;
            return GetCrewmember(root, out success);
        }
        #endregion
    }
}
